/**
 * <copyright>
 * </copyright>
 *
 * $Id$
 */
package BoardGameLanguage.impl;

import BoardGameLanguage.Board;
import BoardGameLanguage.BoardGameLanguagePackage;
import BoardGameLanguage.Field;
import BoardGameLanguage.Figure;

import BoardGameLanguage.facade.BoardGameUtils;

import de.upb.tools.fca.*;

import de.upb.tools.sdm.*;

import java.lang.reflect.InvocationTargetException;

import java.util.*;

import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.notify.NotificationChain;

import org.eclipse.emf.common.util.EList;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.InternalEObject;

import org.eclipse.emf.ecore.impl.ENotificationImpl;
import org.eclipse.emf.ecore.impl.EObjectImpl;

import org.eclipse.emf.ecore.util.EObjectContainmentWithInverseEList;
import org.eclipse.emf.ecore.util.InternalEList;

/**
 * <!-- begin-user-doc -->
 * An implementation of the model object '<em><b>Board</b></em>'.
 * <!-- end-user-doc -->
 * <p>
 * The following features are implemented:
 * <ul>
 *   <li>{@link BoardGameLanguage.impl.BoardImpl#getFigures <em>Figures</em>}</li>
 *   <li>{@link BoardGameLanguage.impl.BoardImpl#getFields <em>Fields</em>}</li>
 *   <li>{@link BoardGameLanguage.impl.BoardImpl#getSelectedFigure <em>Selected Figure</em>}</li>
 *   <li>{@link BoardGameLanguage.impl.BoardImpl#getWidth <em>Width</em>}</li>
 *   <li>{@link BoardGameLanguage.impl.BoardImpl#getHeight <em>Height</em>}</li>
 * </ul>
 * </p>
 *
 * @generated
 */
public class BoardImpl extends EObjectImpl implements Board {
	/**
	 * The cached value of the '{@link #getFigures() <em>Figures</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getFigures()
	 * @generated
	 * @ordered
	 */
	protected EList<Figure> figures;

	/**
	 * The cached value of the '{@link #getFields() <em>Fields</em>}' containment reference list.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getFields()
	 * @generated
	 * @ordered
	 */
	protected EList<Field> fields;

	/**
	 * The cached value of the '{@link #getSelectedFigure() <em>Selected Figure</em>}' reference.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getSelectedFigure()
	 * @generated
	 * @ordered
	 */
	protected Figure selectedFigure;

	/**
	 * The default value of the '{@link #getWidth() <em>Width</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getWidth()
	 * @generated
	 * @ordered
	 */
	protected static final int WIDTH_EDEFAULT = 0;

	/**
	 * The cached value of the '{@link #getWidth() <em>Width</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getWidth()
	 * @generated
	 * @ordered
	 */
	protected int width = WIDTH_EDEFAULT;

	/**
	 * The default value of the '{@link #getHeight() <em>Height</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getHeight()
	 * @generated
	 * @ordered
	 */
	protected static final int HEIGHT_EDEFAULT = 0;

	/**
	 * The cached value of the '{@link #getHeight() <em>Height</em>}' attribute.
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @see #getHeight()
	 * @generated
	 * @ordered
	 */
	protected int height = HEIGHT_EDEFAULT;

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	protected BoardImpl() {
		super();
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	protected EClass eStaticClass() {
		return BoardGameLanguagePackage.Literals.BOARD;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<Figure> getFigures() {
		if (figures == null) {
			figures = new EObjectContainmentWithInverseEList<Figure>(
					Figure.class, this,
					BoardGameLanguagePackage.BOARD__FIGURES,
					BoardGameLanguagePackage.FIGURE__BOARD);
		}
		return figures;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public EList<Field> getFields() {
		if (fields == null) {
			fields = new EObjectContainmentWithInverseEList<Field>(Field.class,
					this, BoardGameLanguagePackage.BOARD__FIELDS,
					BoardGameLanguagePackage.FIELD__BOARD);
		}
		return fields;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Figure getSelectedFigure() {
		if (selectedFigure != null && selectedFigure.eIsProxy()) {
			InternalEObject oldSelectedFigure = (InternalEObject) selectedFigure;
			selectedFigure = (Figure) eResolveProxy(oldSelectedFigure);
			if (selectedFigure != oldSelectedFigure) {
				if (eNotificationRequired())
					eNotify(new ENotificationImpl(this, Notification.RESOLVE,
							BoardGameLanguagePackage.BOARD__SELECTED_FIGURE,
							oldSelectedFigure, selectedFigure));
			}
		}
		return selectedFigure;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public Figure basicGetSelectedFigure() {
		return selectedFigure;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setSelectedFigure(Figure newSelectedFigure) {
		Figure oldSelectedFigure = selectedFigure;
		selectedFigure = newSelectedFigure;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET,
					BoardGameLanguagePackage.BOARD__SELECTED_FIGURE,
					oldSelectedFigure, selectedFigure));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public int getWidth() {
		return width;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setWidth(int newWidth) {
		int oldWidth = width;
		width = newWidth;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET,
					BoardGameLanguagePackage.BOARD__WIDTH, oldWidth, width));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public int getHeight() {
		return height;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void setHeight(int newHeight) {
		int oldHeight = height;
		height = newHeight;
		if (eNotificationRequired())
			eNotify(new ENotificationImpl(this, Notification.SET,
					BoardGameLanguagePackage.BOARD__HEIGHT, oldHeight, height));
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void initialize(BoardGameUtils utils) {
		boolean fujaba__Success = false;
		Iterator fujaba__IterThisToAbove = null;
		Field above = null;
		Iterator fujaba__IterThisToBelow = null;
		Field below = null;
		Iterator fujaba__IterThisToLeft = null;
		Field left = null;
		Iterator fujaba__IterThisToRight = null;
		Field right = null;
		Iterator fujaba__IterThisToField = null;
		Field field = null;

		utils.createAllFields(this);
		// story pattern iterate over Fields
		try {
			fujaba__Success = false;

			// iterate to-many link fields from this to field
			fujaba__Success = false;

			fujaba__IterThisToField = new ArrayList(this.getFields())
					.iterator();

			while (fujaba__IterThisToField.hasNext()) {
				try {
					field = (Field) fujaba__IterThisToField.next();

					// check object field is really bound
					JavaSDM.ensure(field != null);
					// story pattern connect current Field
					try {
						fujaba__Success = false;

						// check object field is really bound
						JavaSDM.ensure(field != null);
						// iterate to-many link fields from this to above
						fujaba__Success = false;

						fujaba__IterThisToAbove = this.getFields().iterator();

						while (!(fujaba__Success)
								&& fujaba__IterThisToAbove.hasNext()) {
							try {
								above = (Field) fujaba__IterThisToAbove.next();

								// check optional
								if (above != null) {
									// check isomorphic binding between objects above and field
									JavaSDM.ensure(!above.equals(field));

									// attribute condition
									JavaSDM.ensure(above.getColumn() == field
											.getColumn());

									// attribute condition
									JavaSDM.ensure(above.getRow() == field
											.getRow() - 1);

								}
								fujaba__Success = true;
							} catch (JavaSDMException fujaba__InternalException) {
								fujaba__Success = false;
							}
						}
						if (!fujaba__Success) {
							fujaba__Success = true;
							above = null;
						}
						// iterate to-many link fields from this to below
						fujaba__Success = false;

						fujaba__IterThisToBelow = this.getFields().iterator();

						while (!(fujaba__Success)
								&& fujaba__IterThisToBelow.hasNext()) {
							try {
								below = (Field) fujaba__IterThisToBelow.next();

								// check optional
								if (below != null) {
									// check isomorphic binding between objects below and field
									JavaSDM.ensure(!below.equals(field));

									// attribute condition
									JavaSDM.ensure(below.getColumn() == field
											.getColumn());

									// attribute condition
									JavaSDM.ensure(below.getRow() == field
											.getRow() + 1);

								}
								fujaba__Success = true;
							} catch (JavaSDMException fujaba__InternalException) {
								fujaba__Success = false;
							}
						}
						if (!fujaba__Success) {
							fujaba__Success = true;
							below = null;
						}
						// iterate to-many link fields from this to left
						fujaba__Success = false;

						fujaba__IterThisToLeft = this.getFields().iterator();

						while (!(fujaba__Success)
								&& fujaba__IterThisToLeft.hasNext()) {
							try {
								left = (Field) fujaba__IterThisToLeft.next();

								// check optional
								if (left != null) {
									// check isomorphic binding between objects left and field
									JavaSDM.ensure(!left.equals(field));

									// attribute condition
									JavaSDM.ensure(left.getColumn() == field
											.getColumn() - 1);

									// attribute condition
									JavaSDM.ensure(left.getRow() == field
											.getRow());

								}
								fujaba__Success = true;
							} catch (JavaSDMException fujaba__InternalException) {
								fujaba__Success = false;
							}
						}
						if (!fujaba__Success) {
							fujaba__Success = true;
							left = null;
						}
						// iterate to-many link fields from this to right
						fujaba__Success = false;

						fujaba__IterThisToRight = this.getFields().iterator();

						while (!(fujaba__Success)
								&& fujaba__IterThisToRight.hasNext()) {
							try {
								right = (Field) fujaba__IterThisToRight.next();

								// check optional
								if (right != null) {
									// check isomorphic binding between objects right and field
									JavaSDM.ensure(!right.equals(field));

									// attribute condition
									JavaSDM.ensure(right.getColumn() == field
											.getColumn() + 1);

									// attribute condition
									JavaSDM.ensure(right.getRow() == field
											.getRow());

								}
								fujaba__Success = true;
							} catch (JavaSDMException fujaba__InternalException) {
								fujaba__Success = false;
							}
						}
						if (!fujaba__Success) {
							fujaba__Success = true;
							right = null;
						}
						// check optional
						if (above != null) {
							// create link
							field.setAbove(above);

						}// check optional
						if (left != null) {
							// create link
							left.setRight(field);

						}// check optional
						if (below != null) {
							// create link
							below.setAbove(field);

						}// check optional
						if (right != null) {
							// create link
							right.setLeft(field);

						}
						fujaba__Success = true;
					} catch (JavaSDMException fujaba__InternalException) {
						fujaba__Success = false;
					}

					fujaba__Success = true;
				} catch (JavaSDMException fujaba__InternalException) {
					fujaba__Success = false;
				}
			}
			JavaSDM.ensure(fujaba__Success);
			fujaba__Success = true;
		} catch (JavaSDMException fujaba__InternalException) {
			fujaba__Success = false;
		}

		return;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	public void handleFieldPressed(Field field) {
		boolean fujaba__Success = false;
		Figure figureOnField = null;
		Figure selectedFigure = null;

		// story pattern check whether field is occupied
		try {
			fujaba__Success = false;

			// check object field is really bound
			JavaSDM.ensure(field != null);
			// bind object
			figureOnField = field.getFigure();

			// check object figureOnField is really bound
			JavaSDM.ensure(figureOnField != null);

			fujaba__Success = true;
		} catch (JavaSDMException fujaba__InternalException) {
			fujaba__Success = false;
		}

		if (fujaba__Success) {
			// story pattern select figure/change selection
			try {
				fujaba__Success = false;

				// check object figureOnField is really bound
				JavaSDM.ensure(figureOnField != null);
				// create link
				org.moflon.util.eMoflonEMFUtil.addOppositeReference(this,
						figureOnField, "selectedFigure");
				fujaba__Success = true;
			} catch (JavaSDMException fujaba__InternalException) {
				fujaba__Success = false;
			}

		} else {
			// story pattern is there a selected figure?
			try {
				fujaba__Success = false;

				// bind object
				selectedFigure = this.getSelectedFigure();

				// check object selectedFigure is really bound
				JavaSDM.ensure(selectedFigure != null);

				fujaba__Success = true;
			} catch (JavaSDMException fujaba__InternalException) {
				fujaba__Success = false;
			}

			if (fujaba__Success) {
				selectedFigure.move(field);
				// story pattern unselect figure
				try {
					fujaba__Success = false;

					// check object selectedFigure is really bound
					JavaSDM.ensure(selectedFigure != null);
					// check link selectedFigure from this to selectedFigure
					JavaSDM.ensure(selectedFigure.equals(this
							.getSelectedFigure()));

					// destroy link
					org.moflon.util.eMoflonEMFUtil.removeOppositeReference(
							this, selectedFigure, "selectedFigure");
					fujaba__Success = true;
				} catch (JavaSDMException fujaba__InternalException) {
					fujaba__Success = false;
				}

			} else {

			}

		}
		return;
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public NotificationChain eInverseAdd(InternalEObject otherEnd,
			int featureID, NotificationChain msgs) {
		switch (featureID) {
		case BoardGameLanguagePackage.BOARD__FIGURES:
			return ((InternalEList<InternalEObject>) (InternalEList<?>) getFigures())
					.basicAdd(otherEnd, msgs);
		case BoardGameLanguagePackage.BOARD__FIELDS:
			return ((InternalEList<InternalEObject>) (InternalEList<?>) getFields())
					.basicAdd(otherEnd, msgs);
		}
		return super.eInverseAdd(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public NotificationChain eInverseRemove(InternalEObject otherEnd,
			int featureID, NotificationChain msgs) {
		switch (featureID) {
		case BoardGameLanguagePackage.BOARD__FIGURES:
			return ((InternalEList<?>) getFigures())
					.basicRemove(otherEnd, msgs);
		case BoardGameLanguagePackage.BOARD__FIELDS:
			return ((InternalEList<?>) getFields()).basicRemove(otherEnd, msgs);
		}
		return super.eInverseRemove(otherEnd, featureID, msgs);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eGet(int featureID, boolean resolve, boolean coreType) {
		switch (featureID) {
		case BoardGameLanguagePackage.BOARD__FIGURES:
			return getFigures();
		case BoardGameLanguagePackage.BOARD__FIELDS:
			return getFields();
		case BoardGameLanguagePackage.BOARD__SELECTED_FIGURE:
			if (resolve)
				return getSelectedFigure();
			return basicGetSelectedFigure();
		case BoardGameLanguagePackage.BOARD__WIDTH:
			return getWidth();
		case BoardGameLanguagePackage.BOARD__HEIGHT:
			return getHeight();
		}
		return super.eGet(featureID, resolve, coreType);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@SuppressWarnings("unchecked")
	@Override
	public void eSet(int featureID, Object newValue) {
		switch (featureID) {
		case BoardGameLanguagePackage.BOARD__FIGURES:
			getFigures().clear();
			getFigures().addAll((Collection<? extends Figure>) newValue);
			return;
		case BoardGameLanguagePackage.BOARD__FIELDS:
			getFields().clear();
			getFields().addAll((Collection<? extends Field>) newValue);
			return;
		case BoardGameLanguagePackage.BOARD__SELECTED_FIGURE:
			setSelectedFigure((Figure) newValue);
			return;
		case BoardGameLanguagePackage.BOARD__WIDTH:
			setWidth((Integer) newValue);
			return;
		case BoardGameLanguagePackage.BOARD__HEIGHT:
			setHeight((Integer) newValue);
			return;
		}
		super.eSet(featureID, newValue);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public void eUnset(int featureID) {
		switch (featureID) {
		case BoardGameLanguagePackage.BOARD__FIGURES:
			getFigures().clear();
			return;
		case BoardGameLanguagePackage.BOARD__FIELDS:
			getFields().clear();
			return;
		case BoardGameLanguagePackage.BOARD__SELECTED_FIGURE:
			setSelectedFigure((Figure) null);
			return;
		case BoardGameLanguagePackage.BOARD__WIDTH:
			setWidth(WIDTH_EDEFAULT);
			return;
		case BoardGameLanguagePackage.BOARD__HEIGHT:
			setHeight(HEIGHT_EDEFAULT);
			return;
		}
		super.eUnset(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public boolean eIsSet(int featureID) {
		switch (featureID) {
		case BoardGameLanguagePackage.BOARD__FIGURES:
			return figures != null && !figures.isEmpty();
		case BoardGameLanguagePackage.BOARD__FIELDS:
			return fields != null && !fields.isEmpty();
		case BoardGameLanguagePackage.BOARD__SELECTED_FIGURE:
			return selectedFigure != null;
		case BoardGameLanguagePackage.BOARD__WIDTH:
			return width != WIDTH_EDEFAULT;
		case BoardGameLanguagePackage.BOARD__HEIGHT:
			return height != HEIGHT_EDEFAULT;
		}
		return super.eIsSet(featureID);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public Object eInvoke(int operationID, EList<?> arguments)
			throws InvocationTargetException {
		switch (operationID) {
		case BoardGameLanguagePackage.BOARD___INITIALIZE__BOARDGAMEUTILS:
			initialize((BoardGameUtils) arguments.get(0));
			return null;
		case BoardGameLanguagePackage.BOARD___HANDLE_FIELD_PRESSED__FIELD:
			handleFieldPressed((Field) arguments.get(0));
			return null;
		}
		return super.eInvoke(operationID, arguments);
	}

	/**
	 * <!-- begin-user-doc -->
	 * <!-- end-user-doc -->
	 * @generated
	 */
	@Override
	public String toString() {
		if (eIsProxy())
			return super.toString();

		StringBuffer result = new StringBuffer(super.toString());
		result.append(" (width: ");
		result.append(width);
		result.append(", height: ");
		result.append(height);
		result.append(')');
		return result.toString();
	}

} //BoardImpl
